package ajakuulauku;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.StringWriter;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XMLMaster {

   /**
    * Reads from level XML.
    * @param String name Name of the level.
    * @return ArrayList<Object> allData All data concerning the level - magnets, pillars, ball, hole, friction.
    */
	public static ArrayList<Object> read(String name) {
		ArrayList<Object> allData = new ArrayList<Object>();
		try {
			File file = new File("levels/"+name);
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(file);
			doc.getDocumentElement().normalize();
			allData.add(getObject(doc, "magnet"));
			allData.add(getObject(doc, "pillar"));
			allData.add(getObject(doc, "ball"));
			allData.add(getObject(doc, "hole"));
			
			NodeList nodes = doc.getElementsByTagName("other");
			Node physicsNode = nodes.item(0);
			if (physicsNode.getNodeType() == Node.ELEMENT_NODE) {
				Element fricElmnt = (Element)physicsNode;
				NodeList frElmntLst = fricElmnt.getElementsByTagName("friction");
				Element frElmnt = (Element) frElmntLst.item(0);
				NodeList fr = frElmnt.getChildNodes();
				allData.add(Double.parseDouble(fr.item(0).getNodeValue())); // friction
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return allData;
	}
	
	//writes level data to XML, takes level name as argument	
	/**
	 * Writes level data to XML.
	 * @param String name Name of the level
	 * @param ArrayList<GameObject> editorObjects Game objects to be written to XML.
	 */
	public static void Writer(String name, ArrayList<GameObject> editorObjects) {
		String tag;
		try {
			DocumentBuilderFactory documentBuilderFactory = 
	        DocumentBuilderFactory.newInstance();
			DocumentBuilder documentBuilder;
			documentBuilder = documentBuilderFactory.newDocumentBuilder();
			Document document = documentBuilder.newDocument();
			Element rootEl = document.createElement("level");
			document.appendChild(rootEl);
			for(GameObject obj : editorObjects) {
				if(obj instanceof Magnet) tag = "magnet";
				else if(obj instanceof Ball) tag = "ball";
				else if(obj instanceof Hole) tag = "hole";
				else if(obj instanceof Pillar) tag = "pillar";
				else tag = obj.getClass().toString();
				Element objEl = document.createElement(tag);
				Element xEl = document.createElement("locationX");
				xEl.appendChild(document.createTextNode(Double.toString(obj.getX())));
				objEl.appendChild(xEl);
				Element yEl = document.createElement("locationY");
				yEl.appendChild(document.createTextNode(Double.toString(obj.getY())));
				objEl.appendChild(yEl);
				rootEl.appendChild(objEl);
			}
			Element otherEl = document.createElement("other");
			Element frictionEl  = document.createElement("friction");
			frictionEl.appendChild(document.createTextNode(Double.toString(CurrentLevel.friction)));
			otherEl.appendChild(frictionEl);
			rootEl.appendChild(otherEl);
			
			Transformer transformer = TransformerFactory.newInstance().newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			StreamResult result = new StreamResult(new StringWriter());
			DOMSource source = new DOMSource(document);
			transformer.transform(source, result);
			String xmlString = result.getWriter().toString();
			
			File xmlfile= new File("levels/"+name+".xml");
			BufferedWriter writer = null;
			try {
			    writer = new BufferedWriter(new FileWriter(xmlfile));
			    writer.write(xmlString);
			    writer.close();
			}
			catch (Exception e) {
			    e.printStackTrace();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	//generalised method to retrieve objects from XML, takes doc and object type as arguments
	/**
	 * Reads specified objects from XML.
	 * @param Document doc XML document.
	 * @param String type Name of the object in XML.
	 */
	public static double[][] getObject (Document doc, String type) {
		NodeList nodes = doc.getElementsByTagName(type);
		int length = nodes.getLength();
		double [][] object = new double[length][2];
		
		for (int s = 0; s < length; s++) {
			Node fstNode = nodes.item(s);
			if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
				Element fstElmnt = (Element) fstNode;
											
				NodeList locXElmntLst = fstElmnt.getElementsByTagName("locationX");
				Element locXElmnt = (Element) locXElmntLst.item(0);
				NodeList locX = locXElmnt.getChildNodes();
				object[s][0] = Double.parseDouble(locX.item(0).getNodeValue());
				
				NodeList locYElmntLst = fstElmnt.getElementsByTagName("locationY");
				Element locYElmnt = (Element) locYElmntLst.item(0);
				NodeList locY = locYElmnt.getChildNodes();
				object[s][1] = Double.parseDouble(locY.item(0).getNodeValue());				
		    }	
		}
		return object;
	}
}
